package com.hifar.demo3;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.hifar.demo3.exception.S1000DParseException;
import com.hifar.demo3.model.CharacteristicData;
import com.hifar.demo3.model.DmData;
import com.hifar.demo3.model.DmIdent; 
import com.hifar.demo3.model.DmStatus;
import com.hifar.demo3.model.DmTable;
import com.hifar.demo3.model.PreliminaryRequirements;
import com.hifar.demo3.model.ProcedureStep;
import com.hifar.demo3.pojo.SupplyItem;
import com.hifar.demo3.pojo.SupportEquipment;
import com.hifar.demo3.pojo.TableCell;
import com.hifar.demo3.pojo.TableRow;

public class S1000DParser {
    private static final Logger logger = LoggerFactory.getLogger(S1000DParser.class);

    private OperationDataParser operationDataParser;

    // 设置操作数据解析器
    public void setOperationDataParser(OperationDataParser parser) {
        this.operationDataParser = parser;
    }

    public DmData parse(InputStream xmlStream) throws S1000DParseException {
        try {
            // 1. 解析XML文档
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(xmlStream);

            // 2. 创建XPath处理器
            XPathFactory xPathfactory = XPathFactory.newInstance();
            XPath xpath = xPathfactory.newXPath();

            // 3. 构建返回对象
            DmData dmData = new DmData();

            // 4. 解析标识信息
            parseIdentAndStatus(doc, xpath, dmData);

            // 5. 解析内容部分
            parseContent(doc, xpath, dmData);

            return dmData;
        } catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException e) {
            logger.error("解析S1000D DM文件失败", e);
            throw new S1000DParseException("解析S1000D DM文件失败", e);
        }
    }

    private void parseIdentAndStatus(Document doc, XPath xpath, DmData dmData) throws XPathExpressionException {
        // 解析dmCode
        Node dmCodeNode = (Node) xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmIdent/dmCode",
                doc, XPathConstants.NODE);

        DmIdent dmIdent = new DmIdent();
        if (dmCodeNode != null) {
            Map<String, String> dmCodeMap = new HashMap<>();
            for (int i = 0; i < dmCodeNode.getAttributes().getLength(); i++) {
                Node attr = dmCodeNode.getAttributes().item(i);
                dmCodeMap.put(attr.getNodeName(), attr.getNodeValue());
            }
            dmIdent.setDmCode(dmCodeMap);
        }

        // 解析语言信息
        String languageCode = xpath
                .evaluate("/dmodule/identAndStatusSection/dmAddress/dmIdent/language/@languageIsoCode", doc);
        String countryCode = xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmIdent/language/@countryIsoCode",
                doc);
        dmIdent.setLanguageCode(languageCode);
        dmIdent.setCountryCode(countryCode);

        // 解析版本信息
        String issueNumber = xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmIdent/issueInfo/@issueNumber",
                doc);
        dmIdent.setIssueNumber(issueNumber);

        // 解析技术名称
        String techName = xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmAddressItems/dmTitle/techName",
                doc);
        dmIdent.setTechName(techName);

        // 解析发布日期
        String issueDate = xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmAddressItems/issueDate/@year",
                doc) + "-" +
                xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmAddressItems/issueDate/@month", doc) + "-" +
                xpath.evaluate("/dmodule/identAndStatusSection/dmAddress/dmAddressItems/issueDate/@day", doc);
        dmIdent.setIssueDate(issueDate);

        dmData.setDmIdent(dmIdent);

        // 解析状态信息
        DmStatus dmStatus = new DmStatus();
        dmStatus.setSecurityClassification(
                xpath.evaluate("/dmodule/identAndStatusSection/dmStatus/security/@securityClassification", doc));
        dmStatus.setResponsibleCompany(
                xpath.evaluate("/dmodule/identAndStatusSection/dmStatus/responsiblePartnerCompany/@enterpriseCode",
                        doc));
        dmStatus.setOriginator(
                xpath.evaluate("/dmodule/identAndStatusSection/dmStatus/originator/@enterpriseCode", doc));
        dmStatus.setApplicability(
                xpath.evaluate("/dmodule/identAndStatusSection/dmStatus/applic/displayText", doc));

        dmData.setDmStatus(dmStatus);
    }

    private void parseContent(Document doc, XPath xpath, DmData dmData) throws XPathExpressionException {
        // 解析前提要求
        PreliminaryRequirements prelimRequirements = new PreliminaryRequirements();

        // 解析条件
        NodeList conditionNodes = (NodeList) xpath.evaluate(
                "/dmodule/content/procedure/preliminaryRqmts/reqCondGroup/reqCond/condition",
                doc, XPathConstants.NODESET);
        List<String> conditions = new ArrayList<>();
        for (int i = 0; i < conditionNodes.getLength(); i++) {
            conditions.add(conditionNodes.item(i).getTextContent());
        }
        prelimRequirements.setConditions(conditions);

        // 解析供应品
        NodeList supplyNodes = (NodeList) xpath.evaluate(
                "/dmodule/content/procedure/preliminaryRqmts/reqSupplies/supply",
                doc, XPathConstants.NODESET);
        List<SupplyItem> supplies = new ArrayList<>();
        for (int i = 0; i < supplyNodes.getLength(); i++) {
            Node supplyNode = supplyNodes.item(i);
            SupplyItem item = new SupplyItem();
            item.setCode(supplyNode.getAttributes().getNamedItem("code").getNodeValue());
            item.setQuantity(supplyNode.getAttributes().getNamedItem("quantity").getNodeValue());
            item.setDescription(supplyNode.getTextContent());
            supplies.add(item);
        }
        prelimRequirements.setSupplies(supplies);

        // 解析支持设备
        NodeList equipNodes = (NodeList) xpath.evaluate(
                "/dmodule/content/procedure/preliminaryRqmts/reqSupportEquips/supportEquip",
                doc, XPathConstants.NODESET);
        List<SupportEquipment> equipments = new ArrayList<>();
        for (int i = 0; i < equipNodes.getLength(); i++) {
            Node equipNode = equipNodes.item(i);
            SupportEquipment equip = new SupportEquipment();
            equip.setCode(equipNode.getAttributes().getNamedItem("code").getNodeValue());
            equip.setType(equipNode.getAttributes().getNamedItem("supportEquipType").getNodeValue());
            equip.setName(equipNode.getAttributes().getNamedItem("name").getNodeValue());
            equip.setQuantity(equipNode.getAttributes().getNamedItem("quantity").getNodeValue());
            equipments.add(equip);
        }
        prelimRequirements.setSupportEquipments(equipments);

        dmData.setPreliminaryRequirements(prelimRequirements);

        // 解析主程序步骤
        List<ProcedureStep> mainSteps = new ArrayList<>();
        NodeList stepNodes = (NodeList) xpath.evaluate(
                "/dmodule/content/procedure/mainProcedure/procedureStep|/dmodule/content/procedure/mainProcedure/complexProceduralStep",
                doc, XPathConstants.NODESET);

        for (int i = 0; i < stepNodes.getLength(); i++) {
            mainSteps.add(parseProcedureStep(stepNodes.item(i), xpath));
        }

        dmData.setMainProcedureSteps(mainSteps);

        // 解析表格数据
        List<DmTable> tables = new ArrayList<>();
        NodeList tableNodes = (NodeList) xpath.evaluate("//table", doc, XPathConstants.NODESET);

        for (int i = 0; i < tableNodes.getLength(); i++) {
            tables.add(parseTable(tableNodes.item(i), xpath));
        }

        dmData.setTables(tables);

        // 解析特性数据
        List<CharacteristicData> characteristics = new ArrayList<>();
        NodeList charNodes = (NodeList) xpath.evaluate("//gyCharacteristic", doc, XPathConstants.NODESET);

        for (int i = 0; i < charNodes.getLength(); i++) {
            characteristics.add(parseCharacteristic(charNodes.item(i), xpath));
        }

        dmData.setCharacteristics(characteristics);
    }

    private ProcedureStep parseProcedureStep(Node stepNode, XPath xpath) throws XPathExpressionException {
        ProcedureStep step = new ProcedureStep();

        // 解析步骤ID
        if (stepNode.getAttributes().getNamedItem("id") != null) {
            step.setId(stepNode.getAttributes().getNamedItem("id").getNodeValue());
        }

        // 解析标题
        Node titleNode = (Node) xpath.evaluate("title", stepNode, XPathConstants.NODE);
        if (titleNode != null) {
            step.setTitle(titleNode.getTextContent());
        }

        // 解析描述
        Node paraNode = (Node) xpath.evaluate("para", stepNode, XPathConstants.NODE);
        if (paraNode != null) {
            step.setDescription(paraNode.getTextContent());
        }

        // 解析子步骤
        NodeList subStepNodes = (NodeList) xpath.evaluate("proceduralStep", stepNode, XPathConstants.NODESET);
        if (subStepNodes.getLength() > 0) {
            List<ProcedureStep> subSteps = new ArrayList<>();
            for (int i = 0; i < subStepNodes.getLength(); i++) {
                subSteps.add(parseProcedureStep(subStepNodes.item(i), xpath));
            }
            step.setSubSteps(subSteps);
        }
        // 解析并填充操作数据
        NodeList backfillNodes = (NodeList) xpath.evaluate(".//backfillvalue", stepNode, XPathConstants.NODESET);
        for (int i = 0; i < backfillNodes.getLength(); i++) {
            Node backfillNode = backfillNodes.item(i);
            String dataId = backfillNode.getAttributes().getNamedItem("id").getNodeValue();

            if (operationDataParser != null) {
                OperationDataParser.OperationValue opValue = operationDataParser.getOperationValue(dataId);
                if (opValue != null) {
                    step.addOperationData(dataId, opValue.getValue());
                }
            }
        }
        return step;
    }

    private DmTable parseTable(Node tableNode, XPath xpath) throws XPathExpressionException {
        DmTable table = new DmTable();

        // 解析表格ID
        if (tableNode.getAttributes().getNamedItem("id") != null) {
            table.setId(tableNode.getAttributes().getNamedItem("id").getNodeValue());
        }

        // 解析标题
        Node titleNode = (Node) xpath.evaluate("title", tableNode, XPathConstants.NODE);
        if (titleNode != null) {
            table.setTitle(titleNode.getTextContent());
        }

        // 解析行数据
        List<TableRow> rows = new ArrayList<>();
        NodeList rowNodes = (NodeList) xpath.evaluate(".//tr", tableNode, XPathConstants.NODESET);

        for (int i = 0; i < rowNodes.getLength(); i++) {
            Node rowNode = rowNodes.item(i);
            TableRow row = new TableRow();

            if (rowNode.getAttributes().getNamedItem("id") != null) {
                row.setId(rowNode.getAttributes().getNamedItem("id").getNodeValue());
            }

            List<TableCell> cells = new ArrayList<>();
            NodeList cellNodes = (NodeList) xpath.evaluate(".//td|.//th", rowNode, XPathConstants.NODESET);

            for (int j = 0; j < cellNodes.getLength(); j++) {
                Node cellNode = cellNodes.item(j);
                TableCell cell = new TableCell();

                Node paraNode = (Node) xpath.evaluate("para", cellNode, XPathConstants.NODE);
                if (paraNode != null) {
                    cell.setContent(paraNode.getTextContent());
                }

                // 处理合并单元格
                if (cellNode.getAttributes().getNamedItem("colspan") != null) {
                    cell.setColspan(Integer.parseInt(
                            cellNode.getAttributes().getNamedItem("colspan").getNodeValue()));
                }
                
                // 添加对rowspan属性的解析
                if (cellNode.getAttributes().getNamedItem("rowspan") != null) {
                    cell.setRowspan(Integer.parseInt(
                            cellNode.getAttributes().getNamedItem("rowspan").getNodeValue()));
                }

                cells.add(cell);
            }

            row.setCells(cells);
            rows.add(row);
        }

        table.setRows(rows);

        // 在表格中查找并填充操作数据
        NodeList backfillNodes = (NodeList) xpath.evaluate(".//backfillvalue", tableNode, XPathConstants.NODESET);
        for (int i = 0; i < backfillNodes.getLength(); i++) {
            Node backfillNode = backfillNodes.item(i);
            String dataId = backfillNode.getAttributes().getNamedItem("id").getNodeValue();

            if (operationDataParser != null) {
                OperationDataParser.OperationValue opValue = operationDataParser.getOperationValue(dataId);
                if (opValue != null) {
                    // 找到对应的单元格并设置操作值
                    Node parentCell = backfillNode.getParentNode();
                    if (parentCell.getNodeName().equals("td")) {
                        String cellContent = opValue.getValue();
                        if (opValue.getPhoto() != null) {
                            cellContent += " [照片:" + opValue.getPhoto() + "]";
                        }
                        parentCell.setTextContent(cellContent);
                    }
                }
            }
        }

        return table;
    }

    private CharacteristicData parseCharacteristic(Node charNode, XPath xpath) throws XPathExpressionException {
        CharacteristicData charData = new CharacteristicData();

        // 解析ID和类型
        if (charNode.getAttributes().getNamedItem("id") != null) {
            charData.setId(charNode.getAttributes().getNamedItem("id").getNodeValue());
        }
        if (charNode.getAttributes().getNamedItem("characteristicType") != null) {
            charData.setType(charNode.getAttributes().getNamedItem("characteristicType").getNodeValue());
        }

        // 解析标题
        Node titleNode = (Node) xpath.evaluate("characteristicTitle", charNode, XPathConstants.NODE);
        if (titleNode != null) {
            charData.setTitle(titleNode.getTextContent());
        }

        // 解析值信息
        Node valueInfoNode = (Node) xpath.evaluate("characteristicValueInfo", charNode, XPathConstants.NODE);
        if (valueInfoNode != null) {
            if (valueInfoNode.getAttributes().getNamedItem("valueType") != null) {
                charData.setValueType(valueInfoNode.getAttributes().getNamedItem("valueType").getNodeValue());
            }

            Node descNode = (Node) xpath.evaluate("characteristicValueDesc", valueInfoNode, XPathConstants.NODE);
            if (descNode != null) {
                charData.setDescription(descNode.getTextContent());
            }

            Node unitNode = (Node) xpath.evaluate("auxiliaryUnit", valueInfoNode, XPathConstants.NODE);
            if (unitNode != null) {
                charData.setUnit(unitNode.getTextContent());
            }
        }

        // 解析值范围
        Node toleranceNode = (Node) xpath.evaluate(".//tolerance", charNode, XPathConstants.NODE);
        if (toleranceNode != null) {
            Node baseValueNode = (Node) xpath.evaluate("baseValue", toleranceNode, XPathConstants.NODE);
            if (baseValueNode != null) {
                charData.setBaseValue(baseValueNode.getTextContent());
            }

            Node highValueNode = (Node) xpath.evaluate("highValue", toleranceNode, XPathConstants.NODE);
            if (highValueNode != null) {
                charData.setHighValue(highValueNode.getTextContent());
            }

            Node lowValueNode = (Node) xpath.evaluate("lowValue", toleranceNode, XPathConstants.NODE);
            if (lowValueNode != null) {
                charData.setLowValue(lowValueNode.getTextContent());
            }
        }

        return charData;
    }
}